package com.global;

import com.alibaba.fastjson.JSON;
import com.common.global.GlobalDefaultEnum;
import com.common.global.GlobalException;
import com.common.global.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.MissingRequestHeaderException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.sql.SQLDataException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

@RestControllerAdvice
@Slf4j
public class RAdvice implements ResponseBodyAdvice<Object> {

    @Autowired
    private HttpServletRequest request;

    @Value("${server.servlet.context-path:}")
    private String contextPath;
    
    @PostConstruct
    public void init() {
        log.info("！！全局异常捕获已开启！！");
        log.info("！！全局响应封装已加载，拦截所有响应值包成R对象，可用@RAdviceIgnore进行忽略！！");
    }

    /**
     * 决定是否执行beforeBodyWrite()方法
     */
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        String requestUrl = request.getRequestURI();
        AntPathMatcher matcher = new AntPathMatcher();
        for (String ignoreUrl : getIgnoreUrls()) {
            if (matcher.match(ignoreUrl, requestUrl)) {
                return false;
            }
        }
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object r, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        if (null != methodParameter.getMethodAnnotation(RAdviceIgnore.class) || r instanceof R) {
            return r;
        }
        //当返回类型是String时，用的是StringHttpMessageConverter转换器，无法转换为Json格式
        //必须在方法体上标注RequestMapping(produces = "application/json; charset=UTF-8")
        if (r instanceof String) {
            String str = JSON.toJSONString(R.success(r));
            return str;
        }
        return R.success(r);
    }

    private List<String> getIgnoreUrls() {
        List<String> splitIgnoreUrls = new ArrayList<>();
        splitIgnoreUrls.add(contextPath + "/static/");
        // 解决swagger无法访问
        splitIgnoreUrls.add(contextPath + "/swagger-ui.html");
        splitIgnoreUrls.add(contextPath + "/resources/");
        splitIgnoreUrls.add(contextPath + "/swagger-resources/**");
        splitIgnoreUrls.add(contextPath + "/v2/api-docs");
        // 解决swagger的js文件无法访问
        splitIgnoreUrls.add(contextPath + "/webjars/**");
        splitIgnoreUrls.add(contextPath + "/resources/webjars/");
        splitIgnoreUrls.add(contextPath + "/doc.html");
        splitIgnoreUrls.add(contextPath + "/auth/csrf");
        splitIgnoreUrls.add(contextPath + "/favicon.ico");
        splitIgnoreUrls.add(contextPath + "/actuator/**");
        splitIgnoreUrls.add(contextPath + "/*/");
        return splitIgnoreUrls;
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(value = GlobalException.class)
    public R noHandlerFoundExceptionHandler(HttpServletRequest req, GlobalException e) {
        log.info(e.getMessage(), e);
        log.info("---全局GlobalException异常捕获: {}", e.getMessage());
        return R.error(((GlobalException) e).getCode(), e.getMessage(), null);
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(value = RuntimeException.class)
    public R noHandlerFoundExceptionHandler(HttpServletRequest req, RuntimeException e) {
        log.info(e.getMessage(), e);
        log.info("---全局RuntimeException异常捕获: {}", e.getMessage());
        return R.error(GlobalDefaultEnum.DEFAULT_ERROR.code(), e.getMessage(), null);
    }

    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = {SQLException.class, SQLDataException.class})
    public R noHandlerFoundExceptionHandler2(HttpServletRequest req, Exception e) {
        log.info(e.getMessage(), e);
        log.info("---全局SQLException，SQLDataException异常捕获: {}", e.getMessage());
        return R.error(GlobalDefaultEnum.DEFAULT_ERROR2.code(), e.getMessage(), null);
    }

    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = MissingRequestHeaderException.class)
    public R noHandlerFoundExceptionHandler(HttpServletRequest req, MissingRequestHeaderException e) {
        log.info(e.getMessage(), e);
        log.info("---全局MissingRequestHeaderException异常捕获: {}", e.getMessage());
        return R.error(GlobalDefaultEnum.DEFAULT_ERROR3.code(), e.getMessage(), null);
    }

    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = Exception.class)
    public R noHandlerFoundExceptionHandler(HttpServletRequest req, Exception e) {
        log.info(e.getMessage(), e);
        log.info("---全局异常捕获: {}", e.getMessage());
        return R.error(GlobalDefaultEnum.DEFAULT_ERROR.code(), GlobalDefaultEnum.DEFAULT_ERROR.message(), null);
    }


}
